﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using WeLinkHelper.Model;
using WeLinkHelper.Model.OfficialAccount;
using System.Security.Cryptography;

namespace WeLinkHelper.Untils
{
    public class WeLinkUntils
    {
        #region 判断相关安全信息是否过期并获取Token
        public static string getToken(WeLinkInfoModel weLinkInfo)
        {
            try
            {
                var Now = DateTime.Now;
                var tokenCache = TokenCache.tokenList.Find(i => i.client_id == weLinkInfo.client_id);
                if (tokenCache != null)
                {
                    double passSecond = (Now - tokenCache.currentTime).TotalSeconds;
                    if (passSecond <= tokenCache.expires_in)
                        return tokenCache.access_token;
                }
                string strUrl = "https://open.welink.huaweicloud.com/api/auth/v2/tickets";
                WebHeaderCollection headerCollection = new WebHeaderCollection();
                headerCollection.Add("x-wlk-gray", "0");
                var response = WebRequestHelper.PostWebRequest(strUrl, JsonConvert.SerializeObject(weLinkInfo), headerCollection);

                WeLinkTokenResultModel weLinkTokenResult = JsonConvert.DeserializeObject<WeLinkTokenResultModel>(response);
                TokenCache.tokenList.Add(new TokenCacheModel { access_token = weLinkTokenResult.access_token, client_id = weLinkInfo.client_id, expires_in = weLinkTokenResult.expires_in, currentTime = Now });
                return weLinkTokenResult.access_token;
            }
            catch (Exception e)
            {
                throw e;
            }
        }
        #endregion
        /// <summary>
        /// 发送群消息
        /// </summary>
        /// <param name="weLinkInfo"></param>
        /// <param name="groupMsg"></param>
        /// <returns></returns>
        public WeLinkResultMsgModel sendGroupMsg(WeLinkInfoModel weLinkInfo, GroupMsgModel groupMsg)
        {
            try
            {
                praseGroupContent(weLinkInfo, groupMsg);
                string strUrl = "https://open.welink.huaweicloud.com/api/welinkim/v1/im-service/chat/group-chat";
                WebHeaderCollection headerCollection = new WebHeaderCollection();
                headerCollection.Add("x-wlk-Authorization", getToken(weLinkInfo));
                headerCollection.Add("x-wlk-gray", "0");
                var response = WebRequestHelper.PostWebRequest(strUrl, JsonConvert.SerializeObject(groupMsg), headerCollection);
                return JsonConvert.DeserializeObject<WeLinkResultMsgModel>(response);
            }
            catch (Exception ex)
            {
                WeLinkResultMsgModel msgModel = new WeLinkResultMsgModel();
                msgModel.error = new Error() { errorCode = "000001", errorMsg = ex.Message };
                return msgModel;
            }
        }
        private void praseGroupContent1(GroupMsgModel groupMsg)
        {
            string template = string.Empty;
            switch (groupMsg.content_type)
            {
                case 0:
                    template = "<r><n></n><g>0</g><c>&lt;imbody&gt;&lt;imagelist/&gt;&lt;html&gt;&lt;![CDATA[&lt;DIV&gt;{0}&lt;/DIV&gt;]]&gt;&lt;/html&gt;&lt;content&gt;&lt;![CDATA[{0}]]&gt;&lt;/content&gt;&lt;/imbody&gt;</c></r>";
                    groupMsg.content = String.Format(template, HttpUtility.HtmlEncode(groupMsg.content));
                    break;
                case 10:
                    template = @"<r><n></n><g>0</g><c>&lt;imbody&gt;&lt;content&gt;&lt;![CDATA[{{
&quot;title&quot;:&quot;{0}&quot;,
&quot;digest&quot;:&quot;{1}&quot;,
&quot;cardType&quot;:{2},
&quot;cardContext&quot;:{{&quot;isPCDisplay&quot;:&quot;{3}&quot;,
&quot;sourceUrl&quot;:&quot;{4}&quot;,
&quot;handlerUriAndroid&quot;:&quot;{5}&quot;,
&quot;handlerUriIOS&quot;:&quot;{6}&quot;
}}}}]]&gt;&lt;/content&gt;&lt;/imbody&gt;</c></r>";
                    groupMsg.content = String.Format(template
                        , HttpUtility.HtmlEncode(groupMsg.title)
                        , HttpUtility.HtmlEncode(groupMsg.digest)
                        , groupMsg.cardType
                        , groupMsg.isPCDisplay
                        , groupMsg.sourceUrl
                        , groupMsg.handlerUriAndroid ?? groupMsg.sourceUrl
                        , groupMsg.handlerUriIOS ?? groupMsg.sourceUrl
                        ).Trim().Replace("\n", "").Replace("\r", "");
                    break;
                case 1:
                    template = "<imbody><imagelist/><content><![CDATA[{0}]]></content></imbody>";
                    groupMsg.content = String.Format(template, HttpUtility.HtmlEncode(groupMsg.content));
                    break;
                default:
                    break;
            }
        }

        private void praseGroupContent(WeLinkInfoModel weLinkInfo, GroupMsgModel groupMsg)
        {
            switch (groupMsg.content_type)
            {
                case 0:
                    //文本消息
                    groupMsg.content = GroupMsgModel.assembleTextMessage(groupMsg.content); ;
                    break;
                case 10:
                    //card消息
                    groupMsg.content = GroupMsgModel.assembleCardMessage(groupMsg);
                    break;
                case 3:
                    //富媒体消息
                    MediaResource mediaResource = new MediaResource();
                    var res = createLink(weLinkInfo, groupMsg).GetAwaiter().GetResult();
                    string[] nameArr = res.data.fileInfo.Name.Split(".");
                    mediaResource.url = res.data.url;
                    //mediaResource.width = 200;
                    //mediaResource.height = 200;
                    mediaResource.size = res.data.fileInfo.Length;
                    mediaResource.name = nameArr[0] + DateTimeOffset.Now.ToUnixTimeSeconds() +"."+ nameArr[1];
                    mediaResource.accessCode = res.data.access_code;
                    List<string> imageList = new List<string>() {"png","jpeg","jpg","gif" };
                    if (imageList.Contains(nameArr[1].ToLower()))
                    {
                        groupMsg.content_type = 3;
                    }
                    else
                    {
                        groupMsg.content_type = 4;
                    }
                    groupMsg.content = GroupMsgModel.assembleMediaResourceMessage(mediaResource.toUriString());
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 公共号发送普通卡片消息
        /// </summary>
        /// <param name="weLinkInfo"></param>
        /// <param name="cardMsgModel"></param>
        /// <returns></returns>
        public CardMsgResult sendCardMsg(WeLinkInfoModel weLinkInfo, CommonCardMsgModel cardMsgModel)
        {
            try
            {
                UserInfoDetailResult userInfoDetail = getUserInfo(weLinkInfo, cardMsgModel.toUserList);
                cardMsgModel.toUserList = userInfoDetail.data.Select(i => i.userId).ToList();
                string strUrl = "https://open.welink.huaweicloud.com/api/messages/v2/card/common";
                WebHeaderCollection headerCollection = new WebHeaderCollection();
                headerCollection.Add("x-wlk-Authorization", getToken(weLinkInfo));
                headerCollection.Add("x-wlk-gray", "0");
                var response = WebRequestHelper.PostWebRequest(strUrl, JsonConvert.SerializeObject(cardMsgModel), headerCollection);
                return JsonConvert.DeserializeObject<CardMsgResult>(response);
            }
            catch (Exception ex)
            {
                CardMsgResult msgModel = new CardMsgResult();
                msgModel.code = "000001";
                msgModel.message = ex.Message;
                return msgModel;
            }
        }
        /// <summary>
        /// 获取用户信息，通过工号获取userId
        /// </summary>
        /// <param name="weLinkInfo"></param>
        /// <param name="corpUserIds"></param>
        /// <returns></returns>
        public UserInfoDetailResult getUserInfo(WeLinkInfoModel weLinkInfo, List<string> corpUserIds)
        {
            try
            {
                var data = new
                {
                    corpUserIds
                };
                string strUrl = "https://open.welink.huaweicloud.com/api/auth/v1/userids";
                WebHeaderCollection headerCollection = new WebHeaderCollection();
                headerCollection.Add("x-wlk-Authorization", getToken(weLinkInfo));
                headerCollection.Add("x-wlk-gray", "0");
                var response = WebRequestHelper.PostWebRequest(strUrl, JsonConvert.SerializeObject(data), headerCollection);
                return JsonConvert.DeserializeObject<UserInfoDetailResult>(response);
            }
            catch (Exception ex)
            {
                UserInfoDetailResult msgModel = new UserInfoDetailResult();
                msgModel.code = "000002";
                msgModel.message = ex.Message;
                return msgModel;
            }
        }

        /// <summary>
        /// 通过用户工号||手机号获取用户详细信息
        /// </summary>
        /// <param name="weLinkInfo"></param>
        /// <param name="userDetailInfoReq"></param>
        /// <returns></returns>
        public UserDetailInfoResp getUserDetailInfo(WeLinkInfoModel weLinkInfo, UserDetailInfoReq userDetailInfoReq)
        {
            try
            {
                string strUrl = "https://open.welink.huaweicloud.com/api/contact/v2/user/detail";
                WebHeaderCollection headerCollection = new WebHeaderCollection();
                headerCollection.Add("x-wlk-Authorization", getToken(weLinkInfo));
                headerCollection.Add("x-wlk-gray", "0");
                var response = WebRequestHelper.PostWebRequest(strUrl, JsonConvert.SerializeObject(userDetailInfoReq), headerCollection);
                return JsonConvert.DeserializeObject<UserDetailInfoResp>(response);
            }
            catch (Exception ex)
            {
                UserDetailInfoResp msgModel = new UserDetailInfoResp();
                msgModel.code = "000003";
                msgModel.message = ex.Message;
                return msgModel;
            }
        }

        /// <summary>
        /// 群助手推送
        /// </summary>
        /// <param name="weLinkInfo"></param>
        /// <param name="userDetailInfoReq"></param>
        /// <returns></returns>
        public RobotRespResult sendRobotMsg(RobotModel robotModel)
        {
            try
            {
                string strUrl = robotModel.robotUrl;
                var response = WebRequestHelper.PostWebRequest(strUrl, JsonConvert.SerializeObject(robotModel));
                return JsonConvert.DeserializeObject<RobotRespResult>(response);
            }
            catch (Exception ex)
            {
                RobotRespResult msgModel = new RobotRespResult();
                msgModel.code = "000004";
                msgModel.message = ex.Message;
                return msgModel;
            }
        }
        /// <summary>
        /// 图片上传并返回url,作为公众号推送的url图片地址
        /// </summary>
        /// <param name="weLinkInfo"></param>
        /// <param name="userDetailInfoReq"></param>
        /// <returns></returns>
        public async Task<UploadRespResult> uploadFileAsync(string strUrl, WeLinkInfoModel weLinkInfo)
        {
            try
            {
                var response = WebRequestHelper.Upload(strUrl, getToken(weLinkInfo));
                string result = await response.Result.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<UploadRespResult>(result);
            }
            catch (Exception ex)
            {
                UploadRespResult msgModel = new UploadRespResult();
                msgModel.code = "000005";
                msgModel.message = ex.Message;
                return msgModel;
            }
        }

        public async Task<ColuddriveLinkResp> createLink(WeLinkInfoModel weLinkInfo, GroupMsgModel groupMsg)
        {
            try
            {
                string fileUploadUrl = "https://open.welink.huaweicloud.com/api/clouddrive/v1/file/preupload";
                //拿到文件对象
                var res = await WebRequestHelper.getFile(groupMsg.imgUrl,groupMsg.extention);
                //获取临时文件上传地址
                CloudDriveV1PreUploadRequest cloudDriveV1PreUploadRequest = new CloudDriveV1PreUploadRequest();
                cloudDriveV1PreUploadRequest.name = res.Name;
                cloudDriveV1PreUploadRequest.size = res.Length;
                cloudDriveV1PreUploadRequest.md5 = getMd5(res);
                if (res.Length > 256)
                    cloudDriveV1PreUploadRequest.block_md5 = getMd5(res, true);
                WebHeaderCollection headerCollection = new WebHeaderCollection();
                headerCollection.Add("x-wlk-Authorization", getToken(weLinkInfo));
                headerCollection.Add("x-wlk-gray", "0");
                var response = WebRequestHelper.PostWebRequest(fileUploadUrl, JsonConvert.SerializeObject(cloudDriveV1PreUploadRequest), headerCollection);
                CloudDriveV1PreUploadResp clresp = JsonConvert.DeserializeObject<CloudDriveV1PreUploadResp>(response);
                if (string.IsNullOrEmpty(clresp.data.upload_url))
                {
                    if(string.IsNullOrEmpty(clresp.data.file_sn))
                    throw new Exception("未上传成功");

                    //file_sn不为空说明已经上传过，可以直接使用
                }else if(res.Length< 10485760L) //10mb
                {
                    //上传文件
                   var resp =  WebRequestHelper.CloudUpload(res,clresp.data.upload_url,getToken(weLinkInfo)).GetAwaiter().GetResult();
                  string result = await resp.Content.ReadAsStringAsync();
                }
                else
                {
                    //分片上传--目前没有权限
                    //创建分片任务D
                     response = WebRequestHelper.PutWebRequest($"{clresp.data.upload_url}?parts","");
                     WebRequestHelper.uploadPart(clresp.data.upload_url,res);

                }

                string strUrl = "https://open.welink.huaweicloud.com/api/clouddrive/v1/links";
                ColuddriveLink coluddriveLink = new ColuddriveLink();
                coluddriveLink.file_sn = clresp.data.file_sn;
                string accessdata = createAccessCode(20);
                coluddriveLink.plain_access_code = accessdata;
                response = WebRequestHelper.PostWebRequest(strUrl, JsonConvert.SerializeObject(coluddriveLink), headerCollection);
                ColuddriveLinkResp clresp1 = JsonConvert.DeserializeObject<ColuddriveLinkResp>(response);
                clresp1.data.access_code = accessdata;
                clresp1.data.fileInfo = res;
                return clresp1;
            }
            catch (Exception ex)
            {
                ColuddriveLinkResp msgModel = new ColuddriveLinkResp() { code = "000001", message = ex.Message };
                return msgModel;
            }
        }

        /// <summary>
        /// 获取文件MD5
        /// </summary>
        /// <param name="fileInfo"></param>
        /// <param name="isBlock"></param>
        /// <returns></returns>
        private string getMd5(FileInfo fileInfo, bool isBlock = false)
        {
            /***
             * 	文件指纹之取样md5，为进一步避免极小概率可能出现不同文件具有相同md5场景，设计了取样md5。
                超过256KB的文件，取前面256KB计算MD5值。
                超过256字节且不超过256KB的文件，取前面256字节计算MD5值。
                不超过256字节的文件，不需要传递block_md5。
             */
            using (FileStream stream = fileInfo.OpenRead())
            {
                var md5Hasher = new MD5CryptoServiceProvider();
                //非标准
                if (isBlock)
                {
                    byte[] buffer = null;
                    if (fileInfo.Length >= 262144L) // 当已经达到256KB时退出循环
                    {
                        buffer = new byte[1024*256]; // 设置每次读取的缓冲区大小为256字节
                    }
                    else if (fileInfo.Length >= 256L) // 当已经达到256字节时退出循环
                    {
                        buffer = new byte[256]; // 设置每次读取的缓冲区大小为256kb
                    }
                   int l= stream.Read(buffer, 0, buffer.Length);
                    return bytesToHex(md5Hasher.ComputeHash(buffer));
                }
                else
                {
                    //标准
                    byte[] hashBytes = md5Hasher.ComputeHash(stream);
                    return bytesToHex(hashBytes);
                }
            }
        }
        private string bytesToHex(byte[] hashBytes)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hashBytes.Length; i++)
            {
                sb.Append(hashBytes[i].ToString("x2"));
            }
            return sb.ToString();
        }
        private string createAccessCode(int length)
        {
            Random rand = new Random();
            StringBuilder sb = new StringBuilder();
            // 定义要包含在字符串中的字符集合
            char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$^&*-+.".ToCharArray();
            for (int i = 0; i < length; i++)
            {
                int index = rand.Next(chars.Length);
                // 从字符集合中选取一个字符添加到字符串中
                sb.Append(chars[index]);
            }
            return sb.ToString();
        }
    }
}
